package com.Utils3D;

import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Vector;

import objimp.ObjImpFace;
import objimp.ObjImpMesh;
import objimp.ObjImpScene;

import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;


import com.EdificacioAR.DebugLog;
import com.EdificacioAR.Texture;
import com.obj.WavefrontObject;

public class LoaderOBJ extends GenericModelLoader {
	
	public static Model3D loadObjModel(String path) {
		
		//DebugLog.LOGD("LoaderOBJ::loadObjModel - Starting to read obj file: " + path);
		
		return loadModel(path, null);
	}

	public static Model3D loadObjModel(String filename, AssetManager asset) {
		
		DebugLog.LOGD("LoaderOBJ::loadObjModel - Starting to read obj file: " + filename);
		InputStream stream = null;
		
		try {
			
			//DebugLog.LOGD("Loader3ds::load3dsModel - Opening 3ds file: " + filename);
			//stream = asset.open(filename);
			
			int lastIndexMtl = filename.lastIndexOf("/");
			String mtlPath = filename.substring(0, lastIndexMtl + 1); 
			
						
			DebugLog.LOGD("LoaderOBJ::loadObjModel - mtlPath: " + mtlPath);
			
			//WavefrontObject obj = new WavefrontObject(stream, asset, mtlPath);
			ObjImpScene objScene = new ObjImpScene(asset, filename);
			objScene.load(filename);
			
			//Debug
			//DebugLog.LOGD("LoaderOBJ::loadObjScene - Meshes count: " + objScene.get_meshList().size());
			//DebugLog.LOGD("LoaderOBJ::loadObjScene - Vertices count: " + objScene.get_vertexList().size());
			//DebugLog.LOGD("LoaderOBJ::loadObjScene - Normals count: " + objScene.get_normalList().size());
			//DebugLog.LOGD("LoaderOBJ::loadObjScene - Tex Coords count: " + objScene.get_texcoordList().size());
			
			

			Model3D m = new Model3D();

			m.vertices = FloatBuffer.allocate(objScene.get_vertexList().size() * 3 * FLOAT_SIZE_BYTES);
			m.texCoords = FloatBuffer.allocate(objScene.get_vertexList().size() * 2 * FLOAT_SIZE_BYTES);
			m.vertexNormals = FloatBuffer.allocate(objScene.get_vertexList().size() * 3 * FLOAT_SIZE_BYTES);
			m.colors = FloatBuffer.allocate(objScene.get_vertexList().size() * 3 * FLOAT_SIZE_BYTES);
			
			for (int mc=0; mc<objScene.get_meshList().size(); mc++)
			{
				DebugLog.LOGD("LoaderObj::LoadObjModel - start loading group: " + mc);
				
				ObjImpMesh mesh = objScene.get_meshList().get(mc);
				
				if (mesh.getFaceList().size() > 0)
				{								
					MeshGroup group = new MeshGroup();
					String texFile = mesh.getMaterial().get_texFile();
					
					boolean isOccluder = false;
					if (mesh.getMaterial().get_materialName() != null) 
							isOccluder = mesh.getMaterial().get_materialName().startsWith("occluder");
					group.texFile = (texFile == "") ?
							"" : mtlPath + texFile;// Complete path to the texture or empty string if there's no texture
					group.indices = IntBuffer.allocate(mesh.getFaceList().size() * 3 * INTEGER_SIZE_BYTES);
					group.color = mesh.getMaterial().get_diffuse();
					DebugLog.LOGD("LoaderObj::LoadObjModel - before loading texture");
					group.texture = (group.hasTexture()) ?
							Texture.loadTextureFromExternalStorage(group.texFile) : new Texture();//Load texture if needed
					//DebugLog.LOGD("LoaderObj::LoadObjModel - current texFile: " + group.texFile);
					//DebugLog.LOGD("LoaderObj::LoadObjModel - indices count of the current group: " + mesh.getFaceList().size() );
					//DebugLog.LOGD("LoaderObj::LoadObjModel - material name: " + mesh.getMaterial().get_materialName());
					//DebugLog.LOGD("LoaderObj::LoadObjModel - is occluder: " + ((isOccluder) ? "true" : "false"));
					
					for (int f=0; f<mesh.getFaceList().size(); f++)
					{
						ObjImpFace face;
						try {
							//DebugLog.LOGD("LoaderObj::LoadObjModel - Getting face");
							face = mesh.getFaceList().get(f);
						} catch (Exception e2) {
							// TODO Auto-generated catch block
							face = new ObjImpFace();
							DebugLog.LOGD("LoaderObj::LoadObjModel - Error getting face");
						}
						
						try {
							// Add indices to the current mesh group
							//DebugLog.LOGD("LoaderObj::LoadObjModel - Adding indices");
							group.indices.put(face._a);
							group.indices.put(face._b);
							group.indices.put(face._c);
							
						} catch (Exception e1) {
							// TODO Auto-generated catch block
							DebugLog.LOGD("LoaderObj::LoadObjModel - Error adding indices");
						}
						
						try {
							// Add vertices
							//DebugLog.LOGD("LoaderObj::LoadObjModel - Adding vertices");
							m.vertices.put(face._a*3, objScene.get_vertexList().get(face._a)[0]);
							m.vertices.put(face._a*3 + 1, objScene.get_vertexList().get(face._a)[1]);
							m.vertices.put(face._a*3 + 2, objScene.get_vertexList().get(face._a)[2]);
							
							m.vertices.put(face._b*3, objScene.get_vertexList().get(face._b)[0]);
							m.vertices.put(face._b*3 + 1, objScene.get_vertexList().get(face._b)[1]);
							m.vertices.put(face._b*3 + 2, objScene.get_vertexList().get(face._b)[2]);
							
							m.vertices.put(face._c*3, objScene.get_vertexList().get(face._c)[0]);
							m.vertices.put(face._c*3 + 1, objScene.get_vertexList().get(face._c)[1]);
							m.vertices.put(face._c*3 + 2, objScene.get_vertexList().get(face._c)[2]);
						} catch (Exception e) {
							// TODO Auto-generated catch block
							DebugLog.LOGD("LoaderObj::LoadObjModel - Error adding vertices");
						}
						
						try {
							// Add normals
							//DebugLog.LOGD("LoaderObj::LoadObjModel - Adding normals");
							m.vertexNormals.put(face._a*3, objScene.get_normalList().get(face._na)[0]);
							m.vertexNormals.put(face._a*3 + 1, objScene.get_normalList().get(face._na)[1]);
							m.vertexNormals.put(face._a*3 + 2, objScene.get_normalList().get(face._na)[2]);
							
							m.vertexNormals.put(face._b*3, objScene.get_normalList().get(face._nb)[0]);
							m.vertexNormals.put(face._b*3 + 1, objScene.get_normalList().get(face._nb)[1]);
							m.vertexNormals.put(face._b*3 + 2, objScene.get_normalList().get(face._nb)[2]);
							
							m.vertexNormals.put(face._c*3, objScene.get_normalList().get(face._nc)[0]);
							m.vertexNormals.put(face._c*3 + 1, objScene.get_normalList().get(face._nc)[1]);
							m.vertexNormals.put(face._c*3 + 2, objScene.get_normalList().get(face._nc)[2]);
						} catch (Exception e) {
							// TODO Auto-generated catch block
							DebugLog.LOGD("LoaderObj::LoadObjModel - Error adding normals");
						}
						
						try {
							// Add Texture coordinates if needed
							//DebugLog.LOGD("LoaderObj::LoadObjModel - Adding tex coords");
							if (group.hasTexture()) {
								//NOTE: Use 1-v for the v coordinate, to set the origin at the lower left corner (see textureCooParser)
								m.texCoords.put(face._a*2, objScene.get_texcoordList().get(face._ta)[0]);
								m.texCoords.put(face._a*2 + 1, 1-objScene.get_texcoordList().get(face._ta)[1]);
								
								m.texCoords.put(face._b*2, objScene.get_texcoordList().get(face._tb)[0]);
								m.texCoords.put(face._b*2 + 1, 1-objScene.get_texcoordList().get(face._tb)[1]);
								
								m.texCoords.put(face._c*2, objScene.get_texcoordList().get(face._tc)[0]);
								m.texCoords.put(face._c*2 + 1, 1-objScene.get_texcoordList().get(face._tc)[1]);
							}
						} catch (Exception e) {
							// TODO Auto-generated catch block
							DebugLog.LOGD("LoaderObj::LoadObjModel - Error adding tex coords");
						}
						
						try {
							if (!group.hasTexture()) {
								m.colors.put(face._a*3, group.color[0]);
								m.colors.put(face._a*3 + 1, group.color[1]);
								m.colors.put(face._a*3 + 2, group.color[2]);
								
								m.colors.put(face._b*3, group.color[0]);
								m.colors.put(face._b*3 + 1, group.color[1]);
								m.colors.put(face._b*3 + 2, group.color[2]);
								
								m.colors.put(face._c*3, group.color[0]);
								m.colors.put(face._c*3 + 1, group.color[1]);
								m.colors.put(face._c*3 + 2, group.color[2]);
	
							}
						} catch (Exception e) {
							DebugLog.LOGD("LoaderObj::LoadObjModel - Error adding colors");
						}
						
					}
					//DebugLog.LOGD("LoaderObj::LoadObjModel - Group read successfully");
					if (isOccluder) {
						group.texFile = "";// The occluders don't have any texture
						m.occluderGroups.add(group);
					}
					else m.groups.add(group);
				}
				
				//DebugLog.LOGD("LoaderObj::LoadObjModel - tex file: " + texFile);
				//DebugLog.LOGD("LoaderObj::LoadObjModel - has texture: " + group.hasTexture());
			}
			
			objScene = null;//clean resources?
			return m;
		
		
		}
		catch (Exception e) {
			DebugLog.LOGD("LoaderOBJ::loadObjModel - Error loading .obj file: " + e.getMessage());
			e.printStackTrace();
		}
		finally {
			
			 if (stream != null) {
                try {
                     stream.close();
                } catch (IOException e) {}
			
			 }
		}
		return null;
	}
	

}
